package com.zc.manager.device.controller;

import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.zc.manager.device.domain.IotDevice;
import com.zc.manager.device.entity.DeviceEvent;
import com.zc.manager.device.entity.DeviceOperationLogEntity;
import com.zc.manager.device.entity.DeviceProperty;
import com.zc.manager.device.request.DeviceGetPropertiesOperateRequest;
import com.zc.manager.device.request.DeviceOperateRequest;
import com.zc.manager.device.service.IIotDeviceService;
import com.zc.manager.device.service.data.DeviceDataService;
import com.zc.web.api.crud.entity.PagerResult;
import com.zc.web.api.crud.entity.QueryParamEntity;
import io.swagger.v3.oas.annotations.Parameter;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 设备Controller
 *
 * @author xiepufeng
 */
@RestController
@RequestMapping("/api/iot/device")
public class ApiIotDeviceController extends BaseController {

    @Resource
    private IIotDeviceService iotDeviceService;

    @Resource
    private DeviceDataService deviceDataService;


    //*********************************设备增删改查******************************************

    /**
     * 分页查询设备列表
     *
     * @param iotDevice 请求参数
     * @return 分页查询结果
     */
    @GetMapping("list")
    public TableDataInfo listDevice(IotDevice iotDevice) {
        return getDataTable(iotDeviceService.pageDevice(iotDevice));
    }

    /**
     * 无分页查询设备列表
     *
     * @param iotDevice 请求参数
     * @return 查询结果
     */
    @GetMapping("query")
    public AjaxResult queryDevice(IotDevice iotDevice) {
        return AjaxResult.success(iotDeviceService.listDevice(iotDevice));
    }

    /**
     * 根据id查询设备信息
     *
     * @param id 设备id
     * @return 查询结果
     */
    @GetMapping("{id}")
    public AjaxResult getDevice(@PathVariable String id) {
        return AjaxResult.success(iotDeviceService.getDevice(id));
    }

    /**
     * 根据产品id查询设备信息
     *
     * @param productId 产品id
     * @return 查询结果
     */
    @GetMapping("/cache/{productId}")
    public AjaxResult getDeviceCache(@PathVariable String productId) {
        return AjaxResult.success(iotDeviceService.getDeviceCache(productId).collectList().block());
    }

    /**
     * 获取指定ID设备详情
     *
     * @param id 设备id
     * @return 设备详情获取结果
     */
    @GetMapping("/detail/{id}")
    public AjaxResult getDeviceDetailInfo(@PathVariable @Parameter(description = "设备ID") String id) {
        return AjaxResult.success(iotDeviceService.getDeviceDetail(id).block());
    }

    /**
     * 根据条件获取设备数量
     *
     * @param iotDevice 查询条件
     * @return 数量
     */
    @GetMapping("count")
    public AjaxResult getDeviceCount(IotDevice iotDevice) {
        return AjaxResult.success(iotDeviceService.getDeviceCount(iotDevice));
    }


    /**
     * 新增
     *
     * @param iotDevice 新整参数
     * @return 新增操作结果
     */
    @Log(title = "新增设备", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult addDevice(@Valid @RequestBody IotDevice iotDevice) {
        return toAjax(iotDeviceService.addDevice(iotDevice));
    }

    /**
     * 修改
     *
     * @param iotDevice 修改参数
     * @return 修改操作结果
     */
    @Log(title = "修改设备", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult editDevice(@Valid @RequestBody IotDevice iotDevice) {
        return toAjax(iotDeviceService.editDevice(iotDevice));
    }

    /**
     * 删除
     *
     * @param ids 设备id集
     * @return 删除操作结果
     */
    @Log(title = "删除", businessType = BusinessType.DELETE)
    @DeleteMapping("{ids}")
    public AjaxResult removeDevice(@PathVariable List<String> ids) {
        return toAjax(iotDeviceService.removeDevice(ids));
    }

    //*********************************设备导入导出******************************************

    @Log(title = "设备导入", businessType = BusinessType.IMPORT)
    @PostMapping("/import")
    public AjaxResult importDevice(MultipartFile file, boolean updateSupport) throws Exception
    {
        ExcelUtil<IotDevice> util = new ExcelUtil<>(IotDevice.class);
        List<IotDevice> deviceList = util.importExcel(file.getInputStream());
        String message = iotDeviceService.importDevice(deviceList, updateSupport);
        return AjaxResult.success(message);
    }

    //*********************************子设备******************************************

    /**
     * 查询未绑定的子设备
     *
     * @param iotDevice 请求参数
     * @return 分页查询结果
     */
    @GetMapping("/children/list")
    public TableDataInfo listChildrenDevice(IotDevice iotDevice) {
        return getDataTable(iotDeviceService.listChildrenDevice(iotDevice));
    }


    //*********************************设备状态****************************************

    /**
     * 同步设备状态
     *
     * @param ids 设备id集
     * @return 同步操作结果
     */
    @PutMapping("state/sync/{ids}")
    public AjaxResult syncDeviceState(@PathVariable List<String> ids) {
        return AjaxResult.success(iotDeviceService.syncDeviceState(ids));
    }

    /**
     * 同步全部设备状态
     *
     * @return 同步操作结果
     */
    @PutMapping("state/syncAll")
    public AjaxResult syncAllDeviceState() {
        return AjaxResult.success(iotDeviceService.syncAllDeviceState());
    }

    /**
     * 启用设备
     *
     * @param ids 设备id集
     * @return 启用操作结果
     */
    @PutMapping("state/deploy/{ids}")
    public AjaxResult deployDevice(@PathVariable List<String> ids) {
        return toAjax(iotDeviceService.deployDevice(ids));
    }

    /**
     * 启用全部设备
     *
     * @return 启用操作结果
     */
    @PutMapping("state/deployAll")
    public AjaxResult deployAllDevice() {
        return toAjax(iotDeviceService.deployAllDevice());
    }

    /**
     * 停用设备
     *
     * @param ids 设备id集
     * @return 停用操作结果
     */
    @DeleteMapping("state/undeploy/{ids}")
    public AjaxResult undeployDevice(@PathVariable List<String> ids) {
        return toAjax(iotDeviceService.undeployDevice(ids));
    }

    /**
     * 停用全部设备
     *
     * @return 停用操作结果
     */
    @DeleteMapping("state/undeployAll")
    public AjaxResult undeployAllDevice() {
        return toAjax(iotDeviceService.undeployAllDevice());
    }

    /**
     * 断开设备连接
     *
     * @param id 设备id
     * @return 断开设备操作结果
     */
    @DeleteMapping("state/disconnect/{id}")
    public AjaxResult disconnectDevice(@PathVariable String id) {
        return toAjax(iotDeviceService.disconnectDevice(id));
    }

    //*********************************设备日志****************************************

    /**
     * 查询设备日志数据
     *
     * @param deviceId   设备id
     * @param queryParam 查询条件
     * @return 设备日志查询结果
     */
    @GetMapping("/logs/{deviceId}")
    public AjaxResult queryDeviceLog(
            @PathVariable String deviceId,
            @ModelAttribute QueryParamEntity queryParam) {

        Mono<PagerResult<DeviceOperationLogEntity>> pagerResult = deviceDataService.queryDeviceMessageLog(deviceId, queryParam);
        return AjaxResult.success(pagerResult.block());
    }

    //*********************************设备其他配置*************************************

    /**
     * 更新设备配置
     *
     * @param id 设备id
     * @return 更新结果
     */
    @Log(title = "更新设备配置信息", businessType = BusinessType.UPDATE)
    @PutMapping("configuration/{id}")
    public AjaxResult updateConfiguration(@PathVariable String id, @RequestBody String configuration) {
        return AjaxResult.success(iotDeviceService.updateConfiguration(id, configuration));
    }

    /**
     * 重置设备配置
     *
     * @param id 设备id
     * @return 配置重置操作结果
     */
    @Log(title = "重置设备配置信息", businessType = BusinessType.UPDATE)
    @PutMapping("configuration/reset/{id}")
    public AjaxResult resetConfiguration(@PathVariable String id) {
        return AjaxResult.success(iotDeviceService.resetConfiguration(id).block());
    }

    //*********************************设备属性*************************************

    /**
     * 获取指定ID设备最新的全部属性
     *
     * @param deviceId 设备id
     * @return 获取属性数据操作结果
     */
    @GetMapping("/properties/latest/{deviceId}")
    public AjaxResult getDeviceLatestProperties(@PathVariable @Parameter(description = "设备ID") String deviceId) {
        Flux<DeviceProperty> devicePropertyFlux = deviceDataService.queryEachOneProperties(deviceId, QueryParamEntity.of());
        return AjaxResult.success(devicePropertyFlux.collectList().block());
    }

    /**
     * 按条件查询指定ID设备的全部属性
     *
     * @param deviceId   设备id
     * @param queryParam 查询条件
     * @return 获取属性数据操作结果
     */
    @PostMapping("/properties/latest/{deviceId}")
    public AjaxResult getDeviceLatestProperties(@PathVariable @Parameter(description = "设备ID") String deviceId,
                                                @RequestBody QueryParamEntity queryParam) {
        Flux<DeviceProperty> result = deviceDataService.queryEachProperties(deviceId, queryParam);
        return AjaxResult.success(result.collectList().block());
    }

    /**
     * 获取指定ID设备最新的属性
     *
     * @param deviceId   设备id
     * @param propertyId 属性id
     * @return 获取属性数据操作结果
     */
    @GetMapping("/properties/latest/{deviceId}/{propertyId}")
    public AjaxResult getDeviceLatestProperty(@PathVariable @Parameter(description = "设备ID") String deviceId,
                                              @PathVariable @Parameter(description = "属性ID") String propertyId) {
        Mono<DeviceProperty> result = deviceDataService.queryEachOneProperties(deviceId, QueryParamEntity.of(), propertyId)
                .take(1)
                .singleOrEmpty();
        return AjaxResult.success(result.block());
    }

    /**
     * 查询设备指定属性列表
     *
     * @param deviceId   设备id
     * @param propertyId 属性id
     * @param queryParam 查询条件
     * @return 属性列表
     */
    @GetMapping("/properties/history/{deviceId}/{propertyId}")
    public AjaxResult queryDeviceProperties(@PathVariable @Parameter(description = "设备ID") String deviceId,
                                            @PathVariable @Parameter(description = "属性ID") String propertyId,
                                            @Parameter(hidden = true) QueryParamEntity queryParam) {
        Mono<PagerResult<DeviceProperty>> pagerResult = deviceDataService.queryPropertyPage(deviceId, propertyId, queryParam);
        return AjaxResult.success(pagerResult.block());
    }

    /**
     * 获取设备实时属性值
     *
     * @param deviceId   设备id
     * @param propertyId 属性
     * @return 属性实时数据
     */
    @GetMapping("/properties/realtime/{deviceId}/{propertyId}")
    public AjaxResult getDeviceRealtimeProperty(
            @PathVariable String deviceId,
            @PathVariable String propertyId,
            @RequestParam Map<String, Object> headers) {
        Map<String, Object> property = iotDeviceService.getProperty(deviceId, propertyId, headers).block();
        return AjaxResult.success(property);
    }

    /**
     * 批量获取设备实时属性
     *
     * @param deviceId 设备id
     * @param props    属性id集
     * @return 属性实时数据
     */
    @PostMapping("/properties/realtime/{deviceId}")
    public AjaxResult getDeviceRealtimeProperties(
            @PathVariable String deviceId,
            @RequestBody DeviceGetPropertiesOperateRequest props) {

        Map<String, Object> property = iotDeviceService.getProperties(deviceId, props.getBody(), props.getHeaders()).block();
        return AjaxResult.success(property);

    }

    /**
     * 发送设置属性指令到设备
     *
     * @param deviceId 设备id
     * @param props    参数
     * @return 设备属性操作结果
     */
    @PostMapping("/properties/setting/{deviceId}")
    public AjaxResult setDeviceProperties(
            @PathVariable String deviceId,
            @RequestBody DeviceOperateRequest<Map<String, Object>> props
    ) {

        Map<String, Object> writeResult = iotDeviceService.writeProperties(deviceId, props.getBody(), props.getHeaders()).block();

        return AjaxResult.success(writeResult);
    }


    //*********************************设备功能*************************************

    /**
     * 发送调用设备功能指令到设备
     *
     * @param deviceId   设备id
     * @param functionId 功能id
     * @param props      调用参数
     * @return 调用结果
     */
    @PostMapping("/functions/{deviceId}/{functionId}")
    public AjaxResult invokedFunction(
            @PathVariable String deviceId,
            @PathVariable String functionId,
            @RequestBody Map<String, Object> props) {
        return AjaxResult.success(iotDeviceService.invokeFunction(deviceId, functionId, props, new HashMap<>()).collectList().block());
    }

    //*********************************发送指令*************************************

    /**
     * 发送指令到设备
     *
     * @param deviceId 设备id
     * @param props    发送参数
     * @return 指令发送结果
     */
    @PostMapping("/message/{deviceId}")
    public AjaxResult sendMessage(
            @PathVariable String deviceId,
            @RequestBody DeviceOperateRequest<Map<String, Object>> props) {
        return AjaxResult.success(iotDeviceService.sendMessage(deviceId, props.getBody(), props.getHeaders()).collectList().block());
    }

    /**
     * 批量发送指令到设备
     *
     * @param props 指令
     * @return 指令发送结果
     */
    @PostMapping("/messages")
    public AjaxResult sendMessage(
            @RequestBody DeviceOperateRequest<List<Map<String, Object>>> props) {
        return AjaxResult.success(iotDeviceService.sendMessage(props.getDeviceIds(), props.getBody(), props.getHeaders()).collectList().block());
    }

    //*********************************设备事件*************************************


    /**
     * 查询设备事件数据
     *
     * @param deviceId   设备id
     * @param eventId    事件id
     * @param queryParam 查询条件
     * @param format     是否格式化返回结果
     * @return 查询事件结果
     */
    @GetMapping("/events/history/{deviceId}/{eventId}")
    public AjaxResult queryPagerDeviceEvents(
            @PathVariable @Parameter(description = "设备ID") String deviceId,
            @PathVariable @Parameter(description = "事件ID") String eventId,
            @Parameter(hidden = true) QueryParamEntity queryParam,
            @RequestParam(defaultValue = "false")
            @Parameter(description = "是否格式化返回结果,格式化对字段添加_format后缀") boolean format) {

        Mono<PagerResult<DeviceEvent>> pagerResult = deviceDataService.queryEventPage(deviceId, eventId, queryParam, format);
        return AjaxResult.success(pagerResult.block());
    }


    //*********************************物模型*************************************

    /**
     * 获取设备物模型
     *
     * @param id 设备id
     * @return 更新结果
     */
    @GetMapping(value = "/metadata/{id}")
    public AjaxResult getMetadata(@PathVariable String id) {
        return AjaxResult.success(iotDeviceService.getMetadata(id).block());
    }

}
